{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([2., 2., 2.])\n",
      "tensor([2., 2., 4.])\n",
      "None\n",
      "tensor([6., 6., 6.])\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_21597/700981887.py:19: UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at /opt/conda/conda-bld/pytorch_1708026033508/work/build/aten/src/ATen/core/TensorBody.h:489.)\n",
      "  print(y.grad)\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "\n",
    "x1 = torch.randn(3, requires_grad=True)\n",
    "y1 = 2 * x1\n",
    "y1.backward(torch.tensor([1, 1, 1], dtype=torch.float))\n",
    "print(x1.grad)\n",
    "\n",
    "x2 = torch.randn(3, requires_grad=True)\n",
    "y2 = 2 * x2\n",
    "y2.backward(torch.tensor([1, 1, 2], dtype=torch.float))\n",
    "print(x2.grad)\n",
    "\n",
    "x = torch.randn(3, requires_grad=True)\n",
    "y = 2 * x\n",
    "y.requires_grad_(True)\n",
    "z = 3 * y\n",
    "z.backward(torch.tensor([1, 1, 1], dtype=torch.float))\n",
    "print(y.grad)\n",
    "print(x.grad)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "\n",
    "class Net(nn.Module):\n",
    "\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        # 输入图像是单通道，conv1 kenrnel size=5*5，输出通道 6\n",
    "        self.conv1 = nn.Conv2d(1, 6, 5)\n",
    "        # conv2 kernel size=5*5, 输出通道 16\n",
    "        self.conv2 = nn.Conv2d(6, 16, 5)\n",
    "        # 全连接层\n",
    "        self.fc1 = nn.Linear(16*5*5, 120)\n",
    "        self.fc2 = nn.Linear(120, 84)\n",
    "        self.fc3 = nn.Linear(84, 10)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # max-pooling 采用一个 (2,2) 的滑动窗口\n",
    "        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))\n",
    "        # 核(kernel)大小是方形的话，可仅定义一个数字，如 (2,2) 用 2 即可\n",
    "        x = F.max_pool2d(F.relu(self.conv2(x)), 2)\n",
    "        x = x.view(-1, self.num_flat_features(x))\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = F.relu(self.fc2(x))\n",
    "        x = self.fc3(x)\n",
    "        return x\n",
    "\n",
    "    def num_flat_features(self, x):\n",
    "        # 除了 batch 维度外的所有维度\n",
    "        size = x.size()[1:]\n",
    "        num_features = 1\n",
    "        for s in size:\n",
    "            num_features *= s\n",
    "        return num_features\n",
    "\n",
    "net = Net()\n",
    "print(net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "def unpickle(file):\n",
    "    import pickle\n",
    "    with open(file, 'rb') as fo:\n",
    "        dict = pickle.load(fo, encoding='bytes')\n",
    "    return dict\n",
    "\n",
    "meta = unpickle('cifar-10-batches-py/batches.meta')\n",
    "dic1 = unpickle('cifar-10-batches-py/data_batch_1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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amoKbrzxRshms5DP5+FjH/sYVCqVNt7F68dc/RMEAXzmM5+BCy+8EFKpFAwODsKHPvQhOH78ODnHG7l/Thp1BnLPPfcox3HUP/3TP6lnn31W/eEf/qHK5/NqdHT0dDetrVx99dXqrrvuUs8884zavXu3ete73qWGh4dVpVJpfeYTn/iEWrhwodq+fbt64okn1OWXX67e/OY3n8ZWnx4ee+wxtXjxYnXRRRepT33qU63fn8v9MzU1pRYtWqQ+/OEPq507d6r9+/erBx54QL344outz9x+++0ql8up+++/Xz311FPqve99r1qyZImq1+unseXt4bbbblNdXV3qBz/4gTpw4IC69957VTqdVl/96ldbnzmX+ue//uu/1Oc//3n1ve99TwGAuu+++0j9fPrine98p7r44ovVo48+qn7+85+rZcuWqQ9+8INtvpPXh7n6p1AoqE2bNqnvfve76vnnn1c7duxQ69evV2vXriXneCP3z8lyRr58rF+/Xm3ZsqVVDsNQDQ4Oqm3btp3GVp1+xsbGFACohx9+WCn16wEfi8XUvffe2/rMc889pwBA7dix43Q1s+2Uy2W1fPly9ZOf/ET91m/9Vuvl41zvn8985jPqyiuvnLU+iiLV39+v/vZv/7b1u0KhoFzXVf/6r//ajiaeVt797nerj370o+R3119/vbrxxhuVUud2//A/rvPpiz179igAUI8//njrMz/60Y+UYRjq2LFjbWt7O3i5lzPOY489pgBAHTp0SCl1bvXPfDjjZBff92HXrl2wadOm1u9M04RNmzbBjh07TmPLTj/FYhEAADo7OwEAYNeuXRAEAemrlStXwvDw8DnVV1u2bIF3v/vdpB8ApH/+4z/+A9atWwe/+7u/C729vXDppZfCP/7jP7bqDxw4ACMjI6R/crkcbNiw4Zzonze/+c2wfft2eOGFFwAA4KmnnoJHHnkErrnmGgCQ/sHMpy927NgB+Xwe1q1b1/rMpk2bwDRN2LlzZ9vbfLopFotgGAbk83kAkP7hnHFZbScmJiAMQ+jr6yO/7+vrg+eff/40ter0E0UR3HTTTXDFFVfAmjVrAABgZGQEHMdpDe7f0NfXByMjI6ehle3nnnvugV/+8pfw+OOPz6g71/tn//79cOedd8Itt9wCn/vc5+Dxxx+HP/mTPwHHcWDz5s2tPni5uXYu9M9nP/tZKJVKsHLlSrAsC8IwhNtuuw1uvPFGAIBzvn8w8+mLkZER6O3tJfW2bUNnZ+c511+NRgM+85nPwAc/+MFWZlvpH8oZ9/IhvDxbtmyBZ555Bh555JHT3ZQzhiNHjsCnPvUp+MlPfgLxePx0N+eMI4oiWLduHfz1X/81AABceuml8Mwzz8A3vvEN2Lx582lu3enn3/7t3+A73/kO3H333XDBBRfA7t274aabboLBwUHpH+FVEwQB/N7v/R4opeDOO+883c05YznjZJfu7m6wLGuGR8Lo6Cj09/efpladXrZu3Qo/+MEP4Kc//SkMDQ21ft/f3w++70OhUCCfP1f6ateuXTA2NgZvetObwLZtsG0bHn74Yfja174Gtm1DX1/fOd0/AwMDsHr1avK7VatWweHDhwEAWn1wrs61P/3TP4XPfvaz8IEPfAAuvPBC+IM/+AO4+eabYdu2bQAg/YOZT1/09/fD2NgYqW82mzA1NXXO9NdvXjwOHToEP/nJT1q7HgDSP5wz7uXDcRxYu3YtbN++vfW7KIpg+/btsHHjxtPYsvajlIKtW7fCfffdBw8++CAsWbKE1K9duxZisRjpq71798Lhw4fPib666qqr4Omnn4bdu3e3ftatWwc33nhj6/hc7p8rrrhihmv2Cy+8AIsWLQIAgCVLlkB/fz/pn1KpBDt37jwn+qdWq4Fp0iXQsiyIoggApH8w8+mLjRs3QqFQgF27drU+8+CDD0IURbBhw4a2t7nd/ObFY9++ffDf//3f0NXVRerP9f6Zwem2eH057rnnHuW6rvrWt76l9uzZoz7+8Y+rfD6vRkZGTnfT2sof/dEfqVwupx566CF14sSJ1k+tVmt95hOf+IQaHh5WDz74oHriiSfUxo0b1caNG09jq08v2NtFqXO7fx577DFl27a67bbb1L59+9R3vvMdlUwm1b/8y7+0PnP77berfD6vvv/976tf/epX6tprr33DupJyNm/erBYsWNBytf3e976nuru71ac//enWZ86l/imXy+rJJ59UTz75pAIA9Xd/93fqySefbHlrzKcv3vnOd6pLL71U7dy5Uz3yyCNq+fLlbxhX0rn6x/d99d73vlcNDQ2p3bt3k/Xa87zWOd7I/XOynJEvH0op9fd///dqeHhYOY6j1q9frx599NHT3aS2AwAv+3PXXXe1PlOv19Uf//Efq46ODpVMJtX73vc+deLEidPX6NMMf/k41/vnP//zP9WaNWuU67pq5cqV6h/+4R9IfRRF6gtf+ILq6+tTruuqq666Su3du/c0tba9lEol9alPfUoNDw+reDyuzjvvPPX5z3+e/LE4l/rnpz/96cuuN5s3b1ZKza8vJicn1Qc/+EGVTqdVNptVH/nIR1S5XD4Nd3Pqmat/Dhw4MOt6/dOf/rR1jjdy/5wshlIonJ8gCIIgCMLrzBln8yEIgiAIwhsbefkQBEEQBKGtyMuHIAiCIAhtRV4+BEEQBEFoK/LyIQiCIAhCW5GXD0EQBEEQ2oq8fAiCIAiC0Fbk5UMQBEEQhLYiLx+CIAiCILQVefkQBEEQBKGtyMuHIAiCIAht5f8B/fZkq6yJgigAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "horse   dog   cat   dog\n",
      "[1,  2000] loss: 2.203\n",
      "[1,  4000] loss: 1.846\n",
      "[1,  6000] loss: 1.658\n",
      "[1,  8000] loss: 1.578\n",
      "[1, 10000] loss: 1.520\n",
      "[1, 12000] loss: 1.464\n",
      "[2,  2000] loss: 1.408\n",
      "[2,  4000] loss: 1.410\n",
      "[2,  6000] loss: 1.363\n",
      "[2,  8000] loss: 1.308\n",
      "[2, 10000] loss: 1.296\n",
      "[2, 12000] loss: 1.295\n",
      "Finished Training! Total cost time:  112.13677287101746\n",
      "Accuracy of the network on the 10000 test images: 51 %\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "\n",
    "\n",
    "os.chdir(\"/home/husheng/mywork/test\")\n",
    "transform = transforms.Compose(\n",
    "    [transforms.ToTensor(),\n",
    "     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n",
    "\n",
    "trainset = torchvision.datasets.CIFAR10(root='.', train=True,\n",
    "                                        download=False, transform=transform)\n",
    "trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,\n",
    "                                          shuffle=True, num_workers=2)\n",
    "\n",
    "testset = torchvision.datasets.CIFAR10(root='.', train=False,\n",
    "                                       download=False, transform=transform)\n",
    "testloader = torch.utils.data.DataLoader(testset, batch_size=4,\n",
    "                                         shuffle=False, num_workers=2)\n",
    "\n",
    "classes = ('plane', 'car', 'bird', 'cat',\n",
    "           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# 展示图片的函数\n",
    "def imshow(img):\n",
    "    img = img / 2 + 0.5     # 非归一化\n",
    "    npimg = img.numpy()\n",
    "    plt.imshow(np.transpose(npimg, (1, 2, 0)))\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "# 随机获取训练集图片\n",
    "dataiter = iter(trainloader)\n",
    "images, labels = dataiter.__next__()\n",
    "\n",
    "# 展示图片\n",
    "imshow(torchvision.utils.make_grid(images))\n",
    "# 打印图片类别标签\n",
    "print(' '.join('%5s' % classes[labels[j]] for j in range(4)))\n",
    "\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(3, 6, 5)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "        self.conv2 = nn.Conv2d(6, 16, 5)\n",
    "        self.fc1 = nn.Linear(16 * 5 * 5, 120)\n",
    "        self.fc2 = nn.Linear(120, 84)\n",
    "        self.fc3 = nn.Linear(84, 10)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.pool(F.relu(self.conv1(x)))\n",
    "        x = self.pool(F.relu(self.conv2(x)))\n",
    "        x = x.view(-1, 16 * 5 * 5)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = F.relu(self.fc2(x))\n",
    "        x = self.fc3(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "net = Net()\n",
    "\n",
    "import torch.optim as optim\n",
    "\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)\n",
    "\n",
    "import time\n",
    "start = time.time()\n",
    "for epoch in range(2):\n",
    "\n",
    "    running_loss = 0.0\n",
    "    for i, data in enumerate(trainloader, 0):\n",
    "        # 获取输入数据\n",
    "        inputs, labels = data\n",
    "        # 清空梯度缓存\n",
    "        optimizer.zero_grad()\n",
    "\n",
    "        outputs = net(inputs)\n",
    "        loss = criterion(outputs, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "        # 打印统计信息\n",
    "        running_loss += loss.item()\n",
    "        if i % 2000 == 1999:\n",
    "            # 每 2000 次迭代打印一次信息\n",
    "            print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))\n",
    "            running_loss = 0.0\n",
    "print('Finished Training! Total cost time: ', time.time()-start)\n",
    "\n",
    "\n",
    "correct = 0\n",
    "total = 0\n",
    "with torch.no_grad():\n",
    "    for data in testloader:\n",
    "        images, labels = data\n",
    "        outputs = net(images)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    "\n",
    "print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
